If you’re a web developer, it’s in your best interest to know what Typescript is. It’s a programming language that has gained quite a popularity in recent years and by the year 2022, it has been adopted as an option within many frameworks, including React, Angular, and Vue, among others.
Typescript is a superset of Javascript. In simple terms, it is Javascript but with additional typing features.
Okay… and why would you want that? Well, one of the greatest strengths of Javascript is at the same time one of its greatest weaknesses, which is being a loosely typed language.
Javascript offers a lot of versatility, but the price to pay is that it’s easy to generate code with little clarity. In fact, one of the reasons why there are so many memes and jokes on the web about the complexity of Javascript is because most developers have at least one horror story where they encountered a Javascript project done with the worst possible practices.
Typescript comes to offer the advantages of a strongly typed language without sacrificing the versatility of Javascript. It is a middle ground that has gained good acceptance in recent years.
However, it’s likely that, like many others, Typescript hasn’t come into your life because you actively sought it out. In general, most developers came to know Typescript for one of two reasons:
- They started learning Angular (which by default uses Typescript).
- They joined a project that was already using Typescript.
Whatever the reason, the point is that most people start working with Typescript without intending to learn about the language itself.
This kind of situation leads to people doing the same things in Typescript as they do in Javascript, and that ultimately undermines the purpose of the language.
I have come across many projects that don’t even use the basic functionalities of Typescript. So here I’ll show you the minimum that, in my opinion, you should be using in your project.
Typings
let someText: string;
let someNumber: number;
let isFinished: boolean;
let namesList: string[];
let hobbiesList: Array<string>;
let person: {
name: string,
score: number,
classesList: string[],
isConfirmed: boolean
}
Let’s start with the most obvious. If you’re not typing your variables, parameters, and return values, then you shouldn’t be using Typescript.
What’s the point of this?
- You can see it as a way of documenting the code without actually writing documentation.
- It helps you detect data type errors faster.
Just by reading it, your team already knows the purpose of each variable, whether they can be used for arithmetic operations or for concatenations. Moreover, when you compile the code, your program will throw errors if you have made any mistakes.
This is incredibly helpful for more complex objects like person
. Just by seeing the variable declaration without having to inspect more code, we know that a person has a name
, a list of classes (classesList
), a score
, and a confirmation status (isConfirmed
).
By having a clear understanding from the start of what data type each variable holds, you can start getting a clearer idea of the business model the system is built for.
Alias Types/Interfaces
This can simply be seen as a way to implement more complex typing in your code.
In the previous example, we saw that we can define the type of a complex object by opening braces and defining the properties inside it.
let person: {
name: string,
score: number,
classesList: string[],
isConfirmed: boolean
}
It’s obvious that if you’re going to use a variable with that type of object many times it would be tiresome to write the same thing over and over again.
To solve this problem, you can define an Interface or an Alias Type:
Interface
export interface BranchOffice {
branchId: number,
employees: Employee[]
}
export interface Employee {
employeeId: number,
name: string,
age: number,
position: string,
checkIn: () => boolean,
checkOut: () => boolean
}
Alias Type
export type Office = {
branchId: number,
employees: Employee[]
}
export type Employee = {
employeeId: number,
name: string,
age: number,
position: string,
checkIn: () => boolean,
checkOut: () => boolean
}
Both have minimal differences, so you can use either one without worrying too much. Although personally, I prefer Alias Types.
What is important is that I recommend using only one of the two. Mostly to keep your code consistent and clean.
Remember, at the end of the day, the point is to make the code understandable, and if you use both, your team will question whether there was a technical reason for using one over the other.
Generics
Generics allow you to use the same function while changing the input and/or output data type. This allows you to reuse the same code for many cases.
const fetchApi = async <T>(path: string): Promise<T> => {
const response = await fetch(`https://example.com/api${path}`);
return response.json();
}
In this example, we’re calling an API that will return a list of objects. By implementing generics, we can determine what type of object we are handling in the function when we call it. This way, we can reuse the fetch code and make requests to any URL we want without worrying about what type of data the API might return.
We can simply specify the data type we expect to get from the API request:
fetchApi<Employee>('/employees');
fetchApi<Office>('/offices');
And if we make a mistake, Typescript will indicate that the data type is not what was expected. This example will throw an error because the data type returned by the API in /holidays doesn’t match what we defined for the Office
data.
fetchApi<Office>('/holidays');
Enums
Enums are a data type that allows representing constant values with readable names. Each constant can take a numeric or text value, although the default behavior is to assign them a numeric value.
export enum ColorType {
RED,
BLUE,
GREEN,
PURPLE
}
In this case, each element has an assigned value from 0 to 3.
On the other hand, if you want to specify a specific value, you can also do so:
export enum ColorType {
RED = 1,
BLUE = 2,
GREEN = 3,
PURPLE = 4
}
export enum ColorType {
RED = 'RED',
BLUE = 'BLUE',
GREEN = 'GREEN',
PURPLE = 'PURPLE'
}
Reiterating over previous points. The point of using these features is to provide clarity.
Nothing stops you from using simple constants instead of an enum. But enums provide a way to group all the constants of the same type.
For this reason, they are generally used to list the multiple types of values that an element can have, as long as the options are a finite number of elements, of course.
Bonus – Classes
As a bonus, I can’t omit mentioning a very important concept in object-oriented programming (OOP): classes.
A class is intended to group properties and features that belong to an entity. This can be anything that needs to be represented in the system, such as a user, a vehicle, a ticket, etc.
If you’re not familiar with the concept of classes, I recommend reading a bit about OOP, as the concept of “class” is its fundamental part.
The reality is that while it’s an important concept, JavaScript has always been able to handle the concept by itself through the use of prototypes, and it even added the class syntax since ECMAScript 6.
Typescript, of course, also offers this functionality, and although it’s not unique to the language, it’s worth mentioning.
In the end, the point of using Typescript is to use the typing features, and the purpose of having those features to make the code clearer. Not just for you, but for others as well.
Writing good code is an art, and we all have to aim to create code that can be understood just by reading it.